// 2013-9-12上午02:25:47  net.betou.trade.main.manager.agencyorproxy.impl.AdminMngImpl.java

package net.betou.trade.main.manager.agencyorproxy.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.betou.common.hibernate3.Updater;
import net.betou.common.page.Pagination;
import net.betou.common.security.encoder.PwdEncoder;
import net.betou.common.security.encoder.SaltGenerator;
import net.betou.common.security.exception.BadCredentialsException;
import net.betou.common.security.exception.UsernameNotFoundException;
import net.betou.trade.entity.main.AgentAndAdmins;
import net.betou.trade.entity.main.AgentAndAdminsExt;
import net.betou.trade.entity.main.Role;
import net.betou.trade.main.dao.agencyorproxy.AdminDao;
import net.betou.trade.main.manager.AgentAndAdminsExtMng;
import net.betou.trade.main.manager.agencyorproxy.AdminMng;
import net.betou.trade.main.manager.role.AgencyRoleMng;
import net.betou.trade.role.setting.AgentAdminFinderConfig;
import net.betou.trade.web.DBConstants;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 
 * @author 叶装装
 */
@Service
@Transactional
public class AdminMngImpl implements AdminMng{

	@Transactional( readOnly = true )
	public Pagination getPage( AgentAndAdmins admin, String searchProperty, String searchValue, String orderProperty, String orderDirection, int pageNo, int pageSize, String filterStatus ){
		Pagination pagination;
		if( admin.getSystem( ) ){
			pagination = dao.getPage( false, true, null, null, searchProperty, searchValue, orderProperty, orderDirection, pageNo, pageSize, filterStatus );
		}else{

			AgentAdminFinderConfig config = new AgentAdminFinderConfig( admin );

			if( config.isSelf( ) ){
				pagination = dao.getPage( false, true, null, admin.getId( ), searchProperty, searchValue, orderProperty, orderDirection, pageNo, pageSize, filterStatus );
			}else{
				pagination = dao.getPageByCriteria( searchProperty, searchValue, orderProperty, orderDirection, pageNo, pageSize, config.getDeepSQL( ) );
			}
		}

		return pagination;
	}
	
	@SuppressWarnings( "unchecked" )
	@Transactional( readOnly = true )
	public List< Map< String, String > > findListByUserName(  AgentAndAdmins admin,  String username ){
		List< Map< String, String > > jsonDataList = new ArrayList< Map< String, String >>( );
		
		List< AgentAndAdmins > list = ( List< AgentAndAdmins >)dao.getPage( false, null, null, admin.getSystem( ) ? null : admin.getId( ), "username", username, "id", "desc", 1, 10, null ).getList( );
		
		if( list != null && list.size( ) > 0 ){
			
			for( AgentAndAdmins c : list ){
				Map< String, String > result = new HashMap< String, String >( );
				result.put( "name", c.getUsername( ) );
				result.put( "id", String.valueOf( c.getId( ) ) );
				jsonDataList.add( result );
			}
			
		}
		
		return jsonDataList;
	}
	
	@Transactional( readOnly = true )
	public AgentAndAdmins findById( Integer id ){
		return dao.findById( id );
	}
	
	@Transactional( readOnly = true )
	public AgentAndAdmins findAdmin( AgentAndAdmins admin, Integer id ){
		if( admin.getSystem( ) ){
			return dao.findAdmin( id );
		}
		
		return dao.findBySelf( admin.getId( ), id );
	}
	
	@Transactional( readOnly = true )
	public AgentAndAdmins findAdmin( Integer id ){
		return dao.findAdmin( id );
	}
	
	@Transactional( readOnly = true )
	public AgentAndAdmins findByUsername( String username ) {
		return dao.findByUsername( username );
	}
	
	@Transactional( readOnly = true )
	public boolean mobileNotExist( String mobile ) {
		return dao.countByMobile( mobile ) <= 0;
	}

	@Transactional( readOnly = true )
	public boolean nameNotExist( String name ) {
		return dao.countByName( name ) <= 0;
	}

	@Transactional( readOnly = true )
	public boolean userNameNotExist( String username ) {
		return dao.countByUsername( username ) <= 0;
	}
	
	@Transactional( readOnly = true )
	public boolean emailNotExist( String email ) {
		return dao.countByEmail( email ) <= 0;
	}
	
	public AgentAndAdmins update( Boolean disabled, String password, String email, String mobile, AgentAndAdmins bean, AgentAndAdminsExt ext, Integer [ ] roleIds ) {

		if( StringUtils.isNotBlank( password ) ){
			String loginSalt = salt.randomSalt( ); // 重新生成密码混淆

			bean.setSalt( loginSalt );
			bean.setPassword( pwdEncoder.encodePassword( password, loginSalt ) );
		}

		if( disabled == null ){
			bean.setDisabled( true );
		}else{
			bean.setDisabled( false );
		}

		bean.setEmail( StringUtils.isBlank( email ) ? null : email ); // 设置成null
		bean.setMobile( StringUtils.isBlank( mobile ) ? null : mobile );
		
		if( roleIds != null ){
			bean.getRoles( ).clear( ); // 清空角色
			for ( Integer id : roleIds ){
				bean.addToRoles( mng.findById( id ) );
			}
		}
		
		Updater< AgentAndAdmins > updater = new Updater< AgentAndAdmins >( bean );
		updater.include( "email" );
		updater.include( "mobile" );
		
		// 应要求，该功能只被系统角色使用, 该方法有待修改
		beforeUpdate( bean, updater );
		
		bean = dao.updateByUpdater( updater ); // 更新主表
		extMng.update( ext, bean ); // 更新附表

		return bean;
	}
	
	public AgentAndAdmins save( AgentAndAdmins currentAdmin, String ip, Integer [ ] roleIds, AgentAndAdmins bean, AgentAndAdminsExt ext ) {
		bean.setCreateIp( ip );
		bean.setAgencyOrProxy( false );
		String loginSalt = salt.randomSalt( );

		bean.setSalt( loginSalt );
		bean.setPassword( pwdEncoder.encodePassword( bean.getPassword( ), loginSalt ) );

		if( roleIds != null ){
			for ( Integer id : roleIds ){
				bean.addToRoles( mng.findById( id ) );
			}
		}

		bean.saveToAdmin( currentAdmin );

		dao.save( bean );
		extMng.save( ext, bean );

		return bean;
	}
	
	public AgentAndAdmins [ ] deleteByIds( Integer [ ] ids ) {
		AgentAndAdmins [ ] beans = new AgentAndAdmins [ ids.length ];
		for ( int i = 0; i < ids.length; i++ ){
			beans[ i ] = dao.deleteById( ids[ i ] );
		}
		return beans;
	}
	
	public AgentAndAdmins login( String username, String password, String ip ) throws UsernameNotFoundException, BadCredentialsException {
		AgentAndAdmins user = findByUsername( username );

		if( user == null ){
			throw new UsernameNotFoundException( "username not found: " + username );
		}

		if( !pwdEncoder.isPasswordValid( user.getPassword( ), password, user.getSalt( ) ) ){
			throw new BadCredentialsException( "password invalid" );
		}
		// 如果没被禁用，才更新登录次数
		if( !user.getDisabled( ) ){
			// 要存放上次登录的IP. 然后再更新, 所以还需要两个字段，保存上次登录信息的
			updateLoginInfo( user.getId( ), ip );
		}

		return user;
	}

	public void updateLoginInfo( Integer userId, String ip ) {

		AgentAndAdmins user = findById( userId );
		if( user != null ){
			user.setLoginCount( user.getLoginCount( ) + 1 );
			user.setLoginIp( ip );
			user.setLoginDate( new Date( ) );
		}

	}
	
	private void beforeUpdate( AgentAndAdmins bean, Updater< AgentAndAdmins > updater ){
		Set< Role > roles = bean.getRoles( );
		
		if( roles != null && roles.size( ) > 0 ){
			for( Iterator< Role > it = roles.iterator( ); it.hasNext( ); ){
				Role role = it.next( );
				
				if( DBConstants.DEFINED_AGENCY_IDENTITY.equals( role.getIdentity( ) ) ){
					bean.setAgencyOrProxy( true );
					bean.setJustAdmin( false );
					
					updater.include( "agencyOrProxy" );
					updater.include( "justAdmin" );
					
					break;
				}

				if( DBConstants.DEFINED_PROXY_IDENTITY.equals( role.getIdentity( ) ) ){
					bean.setAgencyOrProxy( false );
					bean.setJustAdmin( false );
					updater.include( "agencyOrProxy" );
					updater.include( "justAdmin" );
					break;
				}
				
			}
		}	
	}
	
	@Autowired
	private AdminDao dao;
	
	@Autowired
	private SaltGenerator salt;

	@Autowired
	private PwdEncoder pwdEncoder;
	
	@Autowired
	private AgentAndAdminsExtMng extMng;
	
	@Autowired
	private AgencyRoleMng mng;
}
